package hos.permission;

import android.annotation.SuppressLint;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Build;
import android.util.Log;

import androidx.activity.result.ActivityResultCaller;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.lifecycle.LifecycleOwner;

import java.util.List;

import hos.permission.dialog.RationaleDialog;
import hos.permission.dialog.RationaleDialogFragment;

/**
 * <p>Title: PermissionFragmentHelper </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @version : 1.0
 * @date : 2024-01-10 22:19
 */
public class PermissionFragmentHelper implements PermissionRequest {

    private LifecycleOwner lifecycleOwner;
    private FragmentManager fragmentManager;

    private PermissionFragment permissionFragment;

    /**
     * The origin request orientation of the current Activity. We need to restore it when
     * permission request finished.
     */
    private int originRequestOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;

    private static final String FRAGMENT_TAG = "PermissionFragment";

    @NonNull
    public static PermissionFragmentHelper create(FragmentActivity activity) {
        return new PermissionFragmentHelper(activity);
    }

    @NonNull
    public static PermissionFragmentHelper create(Fragment fragment) {
        return new PermissionFragmentHelper(fragment);
    }

    private PermissionFragmentHelper(@NonNull LifecycleOwner lifecycleOwner) {
        this.lifecycleOwner = lifecycleOwner;
//        lifecycleOwner.getLifecycle().addObserver(new DefaultLifecycleObserver() {
//
//            @Override
//            public void onCreate(@NonNull LifecycleOwner owner) {
//                // 初始化
//            }
//
//            @Override
//            public void onDestroy(@NonNull LifecycleOwner owner) {
////                dispose();
//                owner.getLifecycle().removeObserver(this);
//            }
//        });
    }

    @NonNull
    private FragmentActivity requireActivity() {
        if (lifecycleOwner instanceof FragmentActivity) {
            return (FragmentActivity) lifecycleOwner;
        }
        if (lifecycleOwner instanceof Fragment) {
            return ((Fragment) lifecycleOwner).requireActivity();
        }
        throw new IllegalStateException("PermissionRequest " + this + " null an activity.");
    }

    @NonNull
    private ActivityResultCaller requireActivityResultCaller() {
        if (lifecycleOwner instanceof ActivityResultCaller) {
            return (ActivityResultCaller) lifecycleOwner;
        }
        throw new IllegalStateException("PermissionRequest " + this + " null an ActivityResultCaller.");
    }

    /**
     * Get the FragmentManager if it's in Activity, or the ChildFragmentManager if it's in Fragment.
     *
     * @return The FragmentManager to operate Fragment.
     */
    @NonNull
    private FragmentManager fragmentManager() {
        if (fragmentManager != null) {
            return fragmentManager;
        }
        if (lifecycleOwner instanceof Fragment) {
            return fragmentManager = ((Fragment) lifecycleOwner).getChildFragmentManager();
        }
        if (lifecycleOwner instanceof FragmentActivity) {
            return fragmentManager = ((FragmentActivity) lifecycleOwner).getSupportFragmentManager();
        }
        throw new IllegalStateException("PermissionRequest " + this + " null an FragmentActivity.");
    }

    private PermissionFragment getPermissionFragment() {
        if (permissionFragment != null) {
            return permissionFragment;
        }
        Fragment permissionFragment = fragmentManager().findFragmentByTag(FRAGMENT_TAG);
        if (permissionFragment != null) {
            return this.permissionFragment = (PermissionFragment) permissionFragment;
        }
        PermissionFragment invisibleFragment = new PermissionFragment();
        fragmentManager().beginTransaction()
                .add(invisibleFragment, FRAGMENT_TAG)
                .commitNowAllowingStateLoss();
        fragmentManager().executePendingTransactions();
        return this.permissionFragment = invisibleFragment;
    }

    private PermissionRequest getPermissionRequest() {
        PermissionRequest request = getPermissionFragment().getPermissionRequest();
        lockOrientation();
        request.onSuccessFul(new OnPermissionResultListener.onSuccessFulListener() {
            @Override
            public void onSuccess(PermissionRequest permissionRequest) {
                dispose();
//                new Handler(Looper.getMainLooper())
//                        .postDelayed(new Runnable() {
//                            @Override
//                            public void run() {
//                                dispose();
//                            }
//                        }, 300);
            }
        });
        return request;
    }

    /**
     * Remove the InvisibleFragment from current FragmentManager.
     */
    private void removeFragment() {
        if (fragmentManager == null) {
            return;
        }
        Log.d("Permission", "removeFragment: ");
        Fragment existedFragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG);
        if (existedFragment != null && !existedFragment.isHidden()) {
            fragmentManager.beginTransaction().remove(existedFragment).commitNowAllowingStateLoss();
            fragmentManager.executePendingTransactions();
            permissionFragment = null;
            fragmentManager = null;
        }
    }

    @Override
    public void forwardToSettings() {
        getPermissionRequest().forwardToSettings();
    }

    @Override
    public boolean isSuccess() {
        return getPermissionRequest().isSuccess();
    }

    @NonNull
    @Override
    public PermissionRequest permissions(@NonNull String... permissions) {
        return getPermissionRequest().permissions(permissions);
    }

    @NonNull
    @Override
    public PermissionRequest permissions(@NonNull List<String> permissions) {
        return getPermissionRequest().permissions(permissions);
    }

    @NonNull
    @Override
    public PermissionRequest permission(@NonNull String[] permissions) {
        return getPermissionRequest().permission(permissions);
    }

    @NonNull
    @Override
    public PermissionRequest onRefused(@Nullable OnPermissionResultListener.onRefusedListener refusedListener) {
        return getPermissionRequest().onRefused(refusedListener);
    }

    @NonNull
    @Override
    public PermissionRequest onRefusedDialog(@Nullable OnPermissionResultListener.onRefusedDialogListener refusedDialogListener) {
        return getPermissionRequest().onRefusedDialog(refusedDialogListener);
    }

    @Override
    public PermissionRequest onRequestDialog(@Nullable OnPermissionResultListener.onRequestDialogListener requestDialogListener) {
        return getPermissionRequest().onRequestDialog(requestDialogListener);
    }

    @NonNull
    @Override
    public PermissionRequest onCancel(@Nullable OnPermissionResultListener.onCancelListener cancelListener) {
        return getPermissionRequest().onCancel(cancelListener);
    }

    @NonNull
    @Override
    public PermissionRequest onSuccessFul(@Nullable OnPermissionResultListener.onSuccessFulListener successListener) {
        return getPermissionRequest().onSuccessFul(successListener);
    }

    @NonNull
    @Override
    public PermissionRequest defaultDialog() {
        return getPermissionRequest().defaultDialog();
    }

    @Override
    public void request(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().request(successListener);
    }

    @Override
    public void showPermissionDialog(@NonNull List<String> permissions, @NonNull String message, @NonNull String positiveText, boolean isRequest) {
        getPermissionRequest().showPermissionDialog(permissions, message, positiveText, isRequest);
    }

    @Override
    public void showPermissionDialog(@NonNull List<String> permissions, @NonNull String message, @NonNull String positiveText, @Nullable String negativeText, boolean isRequest) {
        getPermissionRequest().showPermissionDialog(permissions, message, positiveText, negativeText, isRequest);
    }

    @Override
    public void showPermissionDialog(@NonNull RationaleDialog dialog, boolean isRequest) {
        getPermissionRequest().showPermissionDialog(dialog, isRequest);
    }

    @Override
    public void request(boolean isRequest) {
        getPermissionRequest().request(isRequest);
    }

    @Override
    public void showPermissionDialog(@NonNull RationaleDialogFragment dialogFragment, boolean isRequest) {
        getPermissionRequest().showPermissionDialog(dialogFragment, isRequest);
    }

    @Override
    public void requestLocation(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestLocation(successListener);
    }

    @Override
    public void requestLocationBackground(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestLocationBackground(successListener);
    }

    @Override
    public void requestCamera(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestCamera(successListener);
    }

    @Override
    public void requestAudio(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestAudio(successListener);
    }

    @Override
    public void requestAudio_33(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestAudio_33(successListener);
    }

    @Override
    public void requestStorage(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestStorage(successListener);
    }

    @Override
    public void requestStorageR(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestStorageR(successListener);
    }

    @Override
    public void requestReadStorage(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestReadStorage(successListener);
    }

    @Override
    public void requestAllStorage(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestAllStorage(successListener);
    }

    @Override
    public void requestAllStorageCamera(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestAllStorageCamera(successListener);
    }

    @Override
    public void requestPhone(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestPhone(successListener);
    }

    @Override
    public void requestPhoneO(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestPhoneO(successListener);
    }

    @Override
    public void requestContacts(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestContacts(successListener);
    }

    @Override
    public void requestCalendar(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestCalendar(successListener);
    }

    @Override
    public void requestSms(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestSms(successListener);
    }

    @Override
    public void requestReadImage(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestReadImage(successListener);
    }

    @Override
    public void requestReadVideo(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestReadVideo(successListener);
    }

    @Override
    public void requestSystemAlertWindow(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestSystemAlertWindow(successListener);
    }

    @Override
    public void requestWriteSettings(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestWriteSettings(successListener);
    }

    @Override
    public void requestInstallPackages(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestInstallPackages(successListener);
    }

    @Override
    public void requestNotification(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestNotification(successListener);
    }

    @Override
    public void requestBodySensorsBackground(@NonNull OnPermissionResultListener.onSuccessListener successListener) {
        getPermissionRequest().requestBodySensorsBackground(successListener);
    }

    /**
     * Restore the screen orientation. Activity just behave as before locked.
     * Android O has bug that only full screen activity can request orientation,
     * so we need to exclude Android O.
     */
    private void restoreOrientation() {
        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O) {
            requireActivity().setRequestedOrientation(originRequestOrientation);
        }
    }

    /**
     * Lock the screen orientation. Activity couldn't rotate with sensor.
     * Android O has bug that only full screen activity can request orientation,
     * so we need to exclude Android O.
     */
    @SuppressLint("SourceLockedOrientationActivity")
    private void lockOrientation() {
        if (Build.VERSION.SDK_INT != Build.VERSION_CODES.O) {
            originRequestOrientation = requireActivity().getRequestedOrientation();
            int orientation = requireActivity().getResources().getConfiguration().orientation;
            if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
                requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
            } else if (orientation == Configuration.ORIENTATION_PORTRAIT) {
                requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
            }
        }
    }

    @Override
    public void dispose() {
        Log.d("Permission", "dispose");
        removeFragment();
        restoreOrientation();
        lifecycleOwner = null;
    }

    @Override
    public PermissionRequest clearListener() {
        return getPermissionRequest().clearListener();
    }
}
